/*****************************************************************************
 *   Copyright 2005 Tim A Wang
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 ****************************************************************************/
package com.jb.framework.database;

import com.jb.framework.DataSourceManager;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import java.util.Vector;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * Select sql statement
 */
public class SelectDBCommand {
    protected static Log log = LogFactory.getLog(DataSourceManager.class.getName());

    private Predicate predicate;
    private PreparedStatement statement = null;
    private ResultSet resultSet = null;
    private String sql = null;
    private Vector columns = new Vector();

    public SelectDBCommand(String s, Predicate predicate) {
        sql = s;
        this.predicate = predicate;
    }

    public Vector getColumnLabels() {
        return columns;
    }

    public ResultSet getResultSet() {
        return resultSet;
    }

    public boolean absolute(int row) throws SQLException {
        return resultSet.absolute(row);
    }

    public void destroy() throws SQLException {
        if (resultSet != null) {
            resultSet.close();
            resultSet = null;
        }

        if (statement != null) {
            statement.close();
            statement = null;
        }
    }
    /**
     * Execute SQL Command over the connection provided. This method does not 
     * manage transaction. This method keeps an open dataset, you must call destroy
     * method when you are done.
     * @param connection over which the SQL command to be executed.
     * @throws SQLException on database errors.
     */
    public void execute(Connection connection) throws SQLException {
        if(log.isDebugEnabled())
            log.debug("Enter execute");
        if (connection == null) {
            throw new RuntimeException("Failed to get database connection");
        }

        statement = connection.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);

        if (predicate != null) {
            predicate.bindStatement(statement);
        }

        try {
            statement.execute();
            resultSet = statement.getResultSet();
        } catch (SQLException e) {
            if(log.isErrorEnabled())
                log.error("Failed to execute " + this.sql, e);
            throw e;
        }finally {
            if(log.isDebugEnabled())
                log.debug("Leave execute");
        }
    }

    public boolean first() throws SQLException {
        return resultSet.first();
    }

    public boolean last() throws SQLException {
        return resultSet.last();
    }

    public boolean next() throws SQLException {
        return resultSet.next();
    }

    /**
     * This method can be used to populate the visitor object from the result
     * set from database.
     *
     * @param visitor
     *
     * @return
     *
     * @throws SQLException
     */
    public Object populate(Object visitor) throws SQLException {
        return null;
    }

    public boolean previous() throws SQLException {
        return resultSet.previous();
    }

    public boolean relative(int rows) throws SQLException {
        return resultSet.relative(rows);
    }
}
